import logging

import os
from api import models, network
from api.network import UpdateType
from api.pojie_A10.producer_actual_values_A10 import SampleProducer_actual_values_A10
from api.serial.consumer import SampleConsumer
from api.serial.shouji_chuanshu import Shouji_Chuanshu
from detecter import settings

logger = logging.getLogger('serial.order')


class CurrentMould(object):
    __instance = None

    def __init__(self, mould_code, websocket):
        self.is_order_running = False  # producer与consumer同时运行  consumer是否在运行
        self.is_socket_connected = False
        self.mould_code: str = mould_code
        self.websocket = websocket
        # 初始化文件 根据模具编号，创建7个文件夹/文件
        self.good_file, self.unassigned_file, self.sample_path, self.one_hour_temp_file, \
            self.unsend_file, self.rejects_file, self.undetected_file = self.init_data_path()

        # 保持正样本画像
        self.portrait_result = None
        # 数据采集线程
        self.producer = None
        # 建模与检测线程
        self.consumer = None
        # 串口打标签动作监听线程
        self.listener = None
        # django的数据模型类,见models.py; 存有当前工作的模具的信息
        self.prod_mould = None
        # 目前consumer处理的样本， 用于与listener线程同步
        self.prod_sample = None

        self.Shouji_Chuanshu = None

    # 计数加1，往服务器发请求
    @staticmethod
    def add_increment(frame_length=None):
        network.update_product(UpdateType.ADD_GOOD, frame_length=frame_length)

    # 良品加1， 往服务器发请求
    @staticmethod
    def good_increment(frame_length=None):
        network.update_product(UpdateType.ADD_GOOD, frame_length=frame_length)

    # 不良品加1
    @staticmethod
    def bad_increment(frame_length=None):
        network.update_product(UpdateType.ADD_BAD, frame_length=frame_length)

    # 良品+1同时不良品-1 ,说明系统误判
    @staticmethod
    def pos_feedback():
        network.update_product(update_type=UpdateType.POS_FEEDBACK)

    # 不良+1 同时良品-1, 说明系统误判
    @staticmethod
    def neg_feedback():
        network.update_product(UpdateType.NEG_FEEDBACK)

    # 当前模具下的样本标识+1
    def add_sample(self):
        if not self.prod_mould:
            self.prod_mould = models.Mould.objects.get(mould_code=self.mould_code)
        self.prod_mould.sample_id += 1
        self.prod_mould.save()
        return self.prod_mould.sample_id

    @classmethod
    def get_instance(cls):
        return cls.__instance

    @classmethod
    def set_instance(cls, instance=None):
        cls.__instance = instance

    @classmethod
    def new_instance(cls, mould_code, websocket):
        cls.__instance = CurrentMould(mould_code, websocket)
        cls.__instance.is_order_running = True
        cls.__instance.is_socket_connected = True
        return cls.__instance

    # 初始化文件路径, data/sample/{模具编号}/
    # accepted.csv存有正样本
    # unassigned.csv存有未指定标签的负样本
    # one_hour_temp.csv 存有最近一小时的样本数据; 为了另一个功能：制程稳定性
    # unsend.csv 已经检测但因为websocket断了所以没有发送数据的记录

    # rejects.csv 待进行聚类的所有负样本
    # undetected.csv 存有检测的样本
    def init_data_path(self):
        sample_path = os.path.join(settings.BASE_DIR, 'data', 'sample', self.mould_code)
        if not os.path.exists(sample_path):
            os.makedirs(sample_path)
        temp_path = os.path.join(sample_path, 'temp')
        if not os.path.exists(temp_path):
            os.makedirs(temp_path)

        good_file = os.path.join(sample_path, 'accepted.csv')
        unassigned_file = os.path.join(temp_path, 'unassigned.csv')
        one_hour_file = os.path.join(temp_path, 'one_hour_temp.csv')
        unsend_file = os.path.join(temp_path, 'unsend.csv')
        # zxy 修改于 20200103
        rejects_file = os.path.join(sample_path, 'rejects.csv')
        undetected_file = os.path.join(temp_path, 'undetected.csv')

        return good_file, unassigned_file, sample_path, one_hour_file, unsend_file, rejects_file, undetected_file

    def begin_or_continue_order(self, rate_threshold):
        '''
        这个方法在调用的时候，是被一个实例调用的，传进来的self就是实例本身
        '''
        try:
            # 查找模具编号 是否曾经存在过
            mould = models.Mould.objects.get(mould_code=self.mould_code)
            if mould:
                mould.state = 1  # 模具状态赋值为1
                mould.save()
        except Exception as e:  # get如果没有查到，会报错    就创建新模具
            mould = models.Mould.objects.create(mould_code=self.mould_code, state=1, threshold=rate_threshold)
            labels = models.Label.objects.all()
            for label in labels:
                if label.pk != models.Label.default_id and label.pk != models.Label.good_id:
                    models.NegFigure.objects.create(mould=mould, label=label)
        self.prod_mould = mould  # 将模具对象赋值给self.prod_mould(生产模具)
        # 初始化
        try:
            # 工作启动
            self.resume_current_mould(self.prod_mould)
        except Exception as e:
            logger.error(e)

    def resume_current_mould(self, prod_mould):
        # 任务调度线程
        # 主要工作是jobs.py 中的任务, 现暂不启用，后续可增加功能
        # scheduler_thread = ProdSchedule.new_instance()
        # 数据采集模块
        if not self.producer:
            self.producer = SampleProducer_actual_values_A10.new_instance(self)

        if not self.Shouji_Chuanshu:  # 将数据插入数据库的线程。这个线程好像没有用，但是也没启动，
            self.Shouji_Chuanshu = Shouji_Chuanshu.new_instance(self)
        # 恢复正样本画像
        self.portrait_result = prod_mould.get_positive() # 返回值是一个FigureResult实例
        # scheduler_thread.begin()
        # consumer要在producer前启动
        # 建模与检测模块
        self.consumer = SampleConsumer.new_instance(self)
        self.consumer.begin()
        # if not self.Shouji_Chuanshu.is_alive():
        #     self.Shouji_Chuanshu.begin()
        if not self.producer.is_alive():
            self.producer.begin()
        # self.listener.begin()
